import type { ElementType } from "@lib/helper";
import { Slot } from "@lib/Slot";
import {
  type Component,
  type JSXElement,
  type ParentComponent,
  splitProps,
} from "solid-js";
import type { JSX } from "solid-js/jsx-runtime";

interface CardProps extends JSX.HTMLAttributes<HTMLDivElement> {}

const BaseCard: ParentComponent<CardProps> = (props) => {
  const [card, root] = splitProps(props, ["children"]);

  return (
    <div class="card" {...root}>
      {card.children}
    </div>
  );
};

const CardBody: ParentComponent<JSX.HTMLAttributes<HTMLDivElement>> = (
  props
) => {
  const [body, root] = splitProps(props, ["children"]);

  return (
    <div class="card-body" {...root}>
      {body.children}
    </div>
  );
};

const CardHeader: ParentComponent<JSX.HTMLAttributes<HTMLDivElement>> = (
  props
) => {
  const [header, root] = splitProps(props, ["children"]);

  return (
    <div class="card-header" {...root}>
      {header.children}
    </div>
  );
};

const CardFooter: ParentComponent<JSX.HTMLAttributes<HTMLDivElement>> = (
  props
) => {
  const [footer, root] = splitProps(props, ["children"]);

  return (
    <div class="card-footer" {...root}>
      {footer.children}
    </div>
  );
};

type SlotableComponentProps<T extends HTMLElement> = JSX.HTMLAttributes<T> & {
  template?: (props: JSX.HTMLAttributes<T>) => JSXElement;
  children?: JSXElement;
};

const CardTitle = <T extends HTMLElement>(props: SlotableComponentProps<T>) => {
  const [slot, root] = splitProps(props, ["template"]);
  return (
    <Slot
      slot={slot.template}
      context={{
        class: "card-title",
        ...root,
      }}
    >
      {(ctx) => <h5 {...(ctx as any)}></h5>}
    </Slot>
  );
};

const CardSubTitle = <T extends HTMLTitleElement>(
  props: SlotableComponentProps<T>
) => {
  const [slot, root] = splitProps(props, ["template"]);
  return (
    <Slot
      slot={slot.template}
      context={{
        class: "card-subtitle",
        ...root,
      }}
    >
      {(ctx) => <h6 {...(ctx as any)}></h6>}
    </Slot>
  );
};

const CardText = <T extends HTMLParagraphElement>(
  props: SlotableComponentProps<T>
) => {
  const [slot, root] = splitProps(props, ["template"]);
  return (
    <Slot
      slot={slot.template}
      context={{
        class: "card-text",
        ...root,
      }}
    >
      {(ctx) => <p {...(ctx as any)}></p>}
    </Slot>
  );
};

const CardLink = <T extends HTMLLinkElement>(
  props: SlotableComponentProps<T>
) => {
  const [slot, root] = splitProps(props, ["template"]);
  return (
    <Slot
      slot={slot.template}
      context={{
        class: "card-link",
        ...root,
      }}
    >
      {(ctx) => <a {...(ctx as any)}></a>}
    </Slot>
  );
};

const CardImage = <T extends HTMLImageElement>(
  props: JSX.ImgHTMLAttributes<T> & {
    template?: (props: JSX.ImgHTMLAttributes<T>) => JSXElement;
    children?: JSXElement;
  }
) => {
  const [slot, root] = splitProps(props, ["template"]);
  return (
    <Slot
      slot={slot.template}
      context={{
        class: "card-image-top",
        ...root,
      }}
    >
      {(ctx) => <image {...(ctx as any)}></image>}
    </Slot>
  );
};

type CompoundedComponent = typeof BaseCard & {
  Header: typeof CardHeader;
  Body: typeof CardBody;
  Footer: typeof CardFooter;
  Title: typeof CardTitle;
  SubTitle: typeof CardSubTitle;
  Text: typeof CardText;
  Link: typeof CardLink;
  Image: typeof CardImage;
};

const Card = BaseCard as CompoundedComponent;

Card.Header = CardHeader;
Card.Body = CardBody;
Card.Footer = CardFooter;
Card.Title = CardTitle;
Card.SubTitle = CardSubTitle;
Card.Text = CardText;
Card.Link = CardLink;
Card.Image = CardImage;

export default Card;
